/*
 * @Author: 晴鸢. 3013433857@qq.com
 * @Date: 2025-08-29 10:19:32
 * @LastEditors: 晴鸢. 3013433857@qq.com
 * @LastEditTime: 2025-08-31 10:47:22
 * @FilePath: /Learn/pipe_use/processPool.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include"Task.hpp"
#include<string>
#include<vector>
#include<unistd.h>
#include<cstdlib>
#include<ctime>
#include<assert.h>
#include<sys/stat.h>
#include<sys/wait.h>
const int processnum=10;
std::vector<task_t>tasks;//各种任务
//先描述
class channel
{
public:
    channel(int cmdfd,int slaverid,const std::string&processname)
        :_cmdfd(cmdfd)
        ,_slaverid(slaverid)
        ,_processname(processname)
    {}
public:
    int _cmdfd;              //发送任务的文件描述符
    pid_t _slaverid;         //子进程的PID
    std::string _processname;//子进程的名字--方便打日志
    
};

void slaver()
{
    //read(0)
    while(1)
    {
        //std::cout<<getpid()<<" - "<<"read fd is "<<rfd<<std::endl;
        //sleep(1000);
        int cmdcode=0;
        //如果父进程不发送数据，则会阻塞等待
        int n=read(0,&cmdcode,sizeof(int));
        if(n==sizeof(int))
        {
            //执行code对应的任务列表
            std::cout<<getpid()<<" get a command "<<cmdcode<<std::endl;
            if(cmdcode>=0&&cmdcode<tasks.size()) tasks[cmdcode]();
        }
          if(n==0) break;
    }
}

//输入：const &
//输出：*
//输入输出：& 
void Initchannels(std::vector<channel>*channels)
{
    std::vector<int>oldfds;//保存父进程指向的写端
    for(int i=0;i<processnum;i++)
    {
        int pipefd[2];//临时空间（管道）
        int n=pipe(pipefd);//返回0说明成功
        assert(!n);
        (void)n;

        pid_t id=fork();
        //child
        if(id==0)
        {
            for(auto fd:oldfds) close(fd);//确保每一个子进程只有一个写端
            //子进程一直继承读=写端，因此原来的写法会造成下一个子进程会指向上一个子进程的写端
            close(pipefd[1]);
            //重定向
            dup2(pipefd[0],0);
            slaver();
            std::cout<<"process: "<<getpid()<<" quit"<<std::endl;
            exit(0);
        }
        //father
        //写端一直在更新
        close(pipefd[0]);
        //添加channel字段
        std::string name="process-"+std::to_string(i); 
        channels->push_back(channel(pipefd[1],id,name)); 
        oldfds.push_back(pipefd[1]);
    }
}

void debug(const std::vector<channel>&channels)
{
     //test
    for(auto &c:channels)
    {
        std::cout<<c._cmdfd<<" "<<c._slaverid<<" "<<c._processname<<std::endl;
    }
}

void menu()
{
    std::cout<<"####################################"<<std::endl;
    std::cout<<"#1.刷新日志         2.刷新野怪      #"<<std::endl;
    std::cout<<"#3.检测应用是否更新  4.刷新蓝量和血量#"<<std::endl;
    std::cout<<"#                   0.退出         #"<<std::endl;
    std::cout<<"####################################"<<std::endl;
    std::cout<<"Please Enter your choice"<<std::endl;
}

void ctrlslaverid(const std::vector<channel>&channels)
{
    int which=0;
    while(1)
    {
        int select=0;
        menu();
        std::cin>>select;
        if(select<=0||select>4) 
        {
            std::cout<<"Your command is wrong!!!"<<std::endl;
            break;
        }
        //1.选择任务
        //int cmdcode=rand()%tasks.size();
        int cmdcode=select-1;
        //2.选择进程
        //int processnum=rand()%channels.size();
        //3.发送任务
        write(channels[which]._cmdfd,&cmdcode,sizeof(cmdcode)); 
        std::cout<<"father say: "<<"cmdcode:"<<cmdcode<<" already send to"<<
        channels[which]._slaverid<<":"<<channels[which]._processname<<std::endl;
        which++;
        which%=channels.size();
        sleep(1);
    }
}

void Quitprocess(const std::vector<channel>&channels)
{
    for(const auto &c:channels) close(c._cmdfd);
    sleep(5);
    for(const auto &c:channels) waitpid(c._slaverid,nullptr,0);
    sleep(5);
}

int main()
{
    //载入任务
    Loadtask(&tasks);

    srand(time(0));
    //再组织
    std::vector<channel> channels;
    //1.初始化
    Initchannels(&channels);
    //test
    //debug(channels);
    //2.开始控制子进程
    ctrlslaverid(channels);
    //3.清理收尾
    Quitprocess(channels);
    //sleep(1000);

    return 0;
} 